#ifndef FIFO_H
#define FIFO_H

#define FIFOSZ 4096

#include <string>
using namespace std;

template <class T> class fifo {
 private:
  T  *data;
  int  rptr;
  int  wptr;
  int  cursz;
  int  maxsz;
  int  hval;
  int  lval;

  string name;
  size_t size;

 public:
  fifo(const string& n, size_t s);
  virtual ~fifo();
  int  full ();
  void write(T d);
  int  empty();
  T    read ();
  int  len  ();
  void disp_stats();

  // these functions are meant for debugging purposes.
  // they are not members of the fifo class
  template <class T1> friend void showblockfifo(fifo<T1> *b);
  template <class T1> friend void showhuffifo(fifo<T1> *b1, fifo<T1> *b2);

};

//------------------------------------------------------------------------------
#include <iomanip>
#include <iostream>

template <class T>
fifo<T>::fifo(const string& n, size_t s): name(n), size(s) {
  rptr  = 0;
  wptr  = 0;
  data  = new T[size];
  cursz = 0;
  maxsz = 0;
  hval  = 0;
  lval  = 0;
}

template <class T>
fifo<T>::~fifo() {
  delete [] data;
}

template <class T>
int fifo<T>::full() {
  return (((wptr + 1) % size) == rptr);
}

template <class T>
void fifo<T>::write(T d) {
  if (! full()) {
    data[wptr] = d;
    wptr = (wptr + 1) % size;
    cursz += 1;
    if (cursz > maxsz)
      maxsz = cursz;
    if (hval < d)
      hval = d;
    if (lval > d)
      lval = d;
  }
}

template <class T>
int fifo<T>::empty() {
  return (wptr == rptr);
}
 
template <class T>
T fifo<T>::read() {
  T r = 0;
  if (! empty()) {
    r = data[rptr];
    rptr = (rptr + 1) % size;
    cursz -= 1;
  }
  return r;
}

template <class T>
int fifo<T>::len() {
  return cursz;
}

template <class T>
void fifo<T>::disp_stats() {
  cout << "Stats for " << setw(8) << name
       << ": MaxSz " << setw(4) << maxsz
       << " High "   << setw(6) << hval
       << " Low "    << setw(6) << lval << endl;
}

#endif
